////////////////////////////////////////////////////////////////////////////////
//
//  Copyright 2010 galaxy.org
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package org.galaxy.richflex.components
{
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	import mx.binding.utils.BindingUtils;
	import mx.controls.Alert;
	import mx.controls.PopUpButton;
	import mx.controls.Tree;
	import mx.events.DropdownEvent;
	import mx.events.FlexEvent;
	import mx.events.ListEvent;
	import mx.utils.ObjectUtil;
	
	import org.galaxy.richflex.utils.ObjectHelper;
	
	/**
	 * Tree selected changed event.
	 * 
	 * @eventType mx.events.ListEvent.CHANGE
	 */
	[Event(name="change", type="mx.events.ListEvent")]
	
	/**
	 * A button with a tree as pop up component. <code>properties</code> must be set
	 * in order to compare items.
	 * 
	 * @author Cheng Liang
	 * 
	 * @version 0.0.1 create 2010-9-8
	 */
	public class TreePopUpButton extends PopUpButton
	{
		
		// -------------------------------------------------------------------------
		//
		// Properties
		//
		// -------------------------------------------------------------------------
		
		// ------------------------------
		// treeData
		// ------------------------------
		
		private var _treeData : Object;
		
		[Bindable]
		/**
		 * @private
		 */
		public var richflex_internal_treeData : Object;
		
		[Bindable("treeDataChange")]
		/**
		 * @private
		 */
		public function set treeData(value : Object) : void
		{
			if(_treeData != value) {
				_treeData = value;
				richflex_internal_treeData = ObjectUtil.copy(_treeData);
				setParent(richflex_internal_treeData, null);
				dispatchEvent(new Event("treeDataChange"));
			}
		}
		
		/**
		 * Data for tree component.
		 */
		public function get treeData() : Object
		{
			return _treeData;
		}
		
		// ------------------------------
		// labelField
		// ------------------------------
		
		private var _labelField : String;
		
		[Bindable("labelFieldChange")]
		/**
		 * @private
		 */
		public function set labelField(value : String) : void
		{
			if(_labelField != value) {
				_labelField = value;
				dispatchEvent(new Event("labelFieldChange"));
			}
		}
		
		/**
		 * Label field for tree node.
		 */
		public function get labelField() : String
		{
			return _labelField;
		}
		
		// ------------------------------
		// showRoot
		// ------------------------------
		
		private var _showRoot : Boolean;
		
		/**
		 * @private
		 */
		public function set showRoot(value : Boolean) : void
		{
			if(_showRoot != value) {
				_showRoot = value;
			}
		}
		
		/**
		 * Show tree root.
		 */
		public function get showRoot() : Boolean
		{
			return _showRoot;
		}
		
		// ------------------------------
		// selectedItem
		// ------------------------------
		
		private var _selectedItem : Object;
		
		[Bindable("selectedItemChange")]
		/**
		 * @private
		 */
		public function set selectedItem(value : Object) : void
		{
			if(_selectedItem != value) {
				_selectedItem = value;
				this.label = selectedItem[labelField];
				dispatchEvent(new Event("selectedItemChange"));
			}
		}
		
		/**
		 * Selected item of tree.
		 */
		public function get selectedItem() : Object
		{
			return _selectedItem;
		}
		
		// ------------------------------
		// properties
		// ------------------------------
		
		/**
		 * Comparation properties array.
		 */
		public var properties : Array;
		
		// ------------------------------
		// drop down tree
		// ------------------------------
		
		private var treePopUp : Tree;
		
		// -------------------------------------------------------------------------
		//
		// Constructor
		//
		// -------------------------------------------------------------------------
		
		public function TreePopUpButton()
		{
			super();
			// tree pop up
			treePopUp = new Tree();
			treePopUp.setStyle("textAlign", "left");
			treePopUp.addEventListener(ListEvent.CHANGE, onTreePopUpChange);
			BindingUtils.bindProperty(treePopUp, "dataProvider", this, "richflex_internal_treeData");
			
			this.popUp = treePopUp;
			this.setStyle("textAlign", "left");
			addEventListener(FlexEvent.CREATION_COMPLETE, onTreePopUpCreationComplete);
			addEventListener(MouseEvent.CLICK, onMouseClick);
			addEventListener(DropdownEvent.OPEN, onPopUpOpen);
		}
		
		// -------------------------------------------------------------------------
		//
		// Events handlers
		//
		// -------------------------------------------------------------------------
		
		/**
		 * @private
		 */
		protected function onTreePopUpCreationComplete(event : Event) : void
		{
			treePopUp.labelField = labelField;
			treePopUp.showRoot = showRoot;
		}
		
		/**
		 * @private
		 */
		protected function onTreePopUpChange(event : ListEvent) : void
		{
			selectedItem = treePopUp.selectedItem;
			this.label = selectedItem[labelField];
			dispatchEvent(event);
		}
		
		/**
		 * @private
		 */
		protected function onMouseClick(event : MouseEvent) : void
		{
			this.open();
		}
		
		/**
		 * @private
		 */
		protected function onPopUpOpen(event : DropdownEvent) : void
		{
			if(treePopUp) {
				var obj : Object = getTreeItem(richflex_internal_treeData, selectedItem, properties);
				if(obj) {
					treePopUp.expandChildrenOf(obj.parent, true);
					this.label = obj[labelField];
				}
				treePopUp.selectedItem = obj;
				selectedItem = obj;
			}
		}
		
		// -------------------------------------------------------------------------
		//
		// Other functions
		//
		// -------------------------------------------------------------------------
		
		/**
		 * @private
		 * Sets parent properties for all nodes.
		 */
		private function setParent(data : Object, parent : Object) : void
		{
			for each(var o : Object in data){
				if(o != null){
					o.parent = parent;
					setParent(o.children, o);
				}
			}
		}
		
		/**
		 * @private
		 * Gets item from dataProvider of the tree.
		 */
		private function getTreeItem(data : Object, item : Object, properties : Array) : Object
		{
			for each(var o : Object in data){
				if(o != null) {
					if(ObjectHelper.equals(o, item, properties)) {
						return o;
					}
					var result : Object = getTreeItem(o.children, item, properties);
					if(result != null) {
						treePopUp.expandChildrenOf(o, true);
						return result;
					}
				}
			}
			return null;
		}
		
	}
}